package btanalyzer.downloader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.util.Random;

import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import btanalyzer.core.DiggResult;
import btanalyzer.core.DiggResultDiggedSite;
import btanalyzer.core.DiggResultTorrent;
import btanalyzer.core.Digger;

@Component
public class DownloadTaskImpl implements DownloadTask {
	
	private static final String GAMES_CAT_URL_PREFIX = "http://thepiratebay.org/browse/400/";
	private static final String VIDEO_CAT_URL_PREFIX = "http://thepiratebay.org/browse/200/";
	private static final String PROGRAMS_CAT_URL_PREFIX = "http://thepiratebay.org/browse/300/";
	
	private static final String BY_SEEDS_SUFFIX = "/7";
	
	private static final Logger log = LoggerFactory.getLogger(DownloadTaskImpl.class);
	
	@Value("${sitesToDigg}")
	private int sitesToDigg;
	public void setSitesToDigg(int sitesToDigg) {
		this.sitesToDigg = sitesToDigg;
	}
	public int getSitesToDigg() {
		return sitesToDigg;
	}
	
	@Value("${downloadDir}")
	private String downloadDir;
	public void setDownloadDir(String downloadDir) {
		this.downloadDir = downloadDir;
	}
	
	@Value("${numberOfTries}")
	private int numberOfTries;
	public void setNumberOfTries(int numberOfTries) {
		this.numberOfTries = numberOfTries;
	}
	public int getNumberOfTries() {
		return numberOfTries;
	}
	
	@Autowired
	FileDownloader fileDownloader;
	public void setFileDownloader(FileDownloader fileDownloader) {
		this.fileDownloader = fileDownloader;
	}
	public FileDownloader getFileDownloader() {
		return fileDownloader;
	}

	@Autowired
	private Digger digger;
	public void setDigger(Digger digger) {
		this.digger = digger;
	}
	public Digger getDigger() {
		return digger;
	}
	
//	@Scheduled(cron="0 10 0/12 * * ?")
	@Scheduled(fixedRate=60 * 60 * 1000)
	public void run() {
		
		Date startDate = new Date();
		log.info("Donwloading task started, date={}", LogUtils.formatDate(
				startDate));
		
		// create workspace
		String subdir = downloadDir + "/" + DateFormatUtils.format(startDate, "yyyyMMdd_HHmm");
		String htmlDir = subdir + "/html/"; 				// dir to keep html sites
		String metadataDir = subdir + "/metadata/"; 		// dir to keep metadata files
		String infoDir = subdir + "/info/"; 				// dir to keep additional info
		new File(htmlDir).mkdirs();
		new File(metadataDir).mkdirs();
		new File(infoDir).mkdirs();
		
		// create files
		String aboutTaskFilePath = infoDir + "aboutTask.txt";
		File aboutTaskFile = new File(aboutTaskFilePath);
		try {
			aboutTaskFile.createNewFile();
		} catch (IOException e) {
			String errMsg = "Error while creating aboutTaskFile=" + aboutTaskFile.getAbsolutePath();
			log.error(errMsg, e);
			throw new RuntimeException(errMsg, e);
		}
		PrintWriter aboutTaskWriter;
		try {
			aboutTaskWriter = new PrintWriter(aboutTaskFile);
		} catch (FileNotFoundException e) {
			String errMsg = "Error while creating printWriter for aboutTaskFile=" + 
					aboutTaskFile.getAbsolutePath();
			log.error(errMsg, e);
			throw new RuntimeException(errMsg, e);
		}
		
		// start date
		aboutTaskWriter.println("startTimestamp=" + startDate.getTime());
		aboutTaskWriter.println("startDate=" + LogUtils.formatDate(startDate));
		aboutTaskWriter.flush();

		long timeToSleep = 20 * 60 * 1000L;
		
		// TODO pięciokrotne wywołanie
		for (int i = 0; i < getNumberOfTries(); ++i) {
			try {
				downloadHtmls(htmlDir);
				break;
			} catch (Exception e) {
				String errMsg = "Error while downloading htmls try number=" + i + 
						", sleeping " + timeToSleep + " milis";
				log.error(errMsg, e);
				try {
					Thread.sleep(timeToSleep);
				} catch (InterruptedException e1) {
					errMsg = "Error while downloading htmls try number=" + i;
					log.error(errMsg, e1);
					throw new RuntimeException(errMsg, e1);
				}
			}
		}	
		// TODO z zapmiętywaniem, które już zostały pobrane
		for (int i = 0; i < getNumberOfTries(); ++i) {
			try {
				downloadMetadatas(htmlDir, metadataDir);
				break;
			} catch (Exception e) {
				String errMsg = "Error while downloading metadatas try number=" + i + 
						", sleeping " + timeToSleep + " milis";
				log.error(errMsg, e);
				try {
					Thread.sleep(timeToSleep);
				} catch (InterruptedException e1) {
					errMsg = "Error while downloading metadatas try number=" + i;
					log.error(errMsg, e1);
					throw new RuntimeException(errMsg, e1);
				}
			}
		}	
		
		Date stopDate = new Date();
		
		// stop date
		aboutTaskWriter.println("stopTimestamp=" + stopDate.getTime());
		aboutTaskWriter.println("stopDate=" + LogUtils.formatDate(stopDate));
	
		// close all writers
		aboutTaskWriter.close();

		log.info("Donwloading task stopped, date={}",LogUtils.formatDate(
				stopDate));
	}

	/**
	 * @see btanalyzer.downloader.DownloadTask#downloadMetadatas(java.lang.String, java.lang.String)
	 */
	@Override
	public void downloadMetadatas(String htmlDir, String metadataDir) {
		List<DiggResult> digRess = getDigger().digg(htmlDir);
		for (DiggResult diggResult : digRess) {
			DiggResultDiggedSite diggedSite = diggResult.getDiggResultDiggedSite();
			List<DiggResultTorrent> torrents = diggResult.getDiggResultTorrents();
			
			log.debug("Trying to dwonload {} torrents form digged htmlPath={}",
					torrents.size(), diggedSite.getHtmlFilePath());
			
			for (DiggResultTorrent torrent : torrents) {
				String filePath = metadataDir + "/" + torrent.getFileName();
				log.debug("Downloading url={}, filePath={}", torrent.getUrl(), filePath);
				if (!getFileDownloader().download(torrent.getUrl(), filePath)) {
					log.error("Error while downloading metadata url={}", 
							torrent.getUrl());
					throw new RuntimeException("Error while downloading metadata, see logs for more info");
				}
			}
			
		}
		
	}
	
	/**
	 * @see btanalyzer.downloader.DownloadTask#downloadHtmls(java.lang.String)
	 */
	@Override
	public void downloadHtmls(String htmlDir) {
		
		String[] urlPrefixes = {
				GAMES_CAT_URL_PREFIX,
				PROGRAMS_CAT_URL_PREFIX,
				VIDEO_CAT_URL_PREFIX
		};
		String urlSuffix = BY_SEEDS_SUFFIX;
		
		log.info("downloading {} sites for {} categories", getSitesToDigg(), 
				urlPrefixes.length);
		
		Random rand = new Random();
		
		for (int i = 0; i < urlPrefixes.length; i++) {
			String urlPrefix = urlPrefixes[i];
			for (int j = 0; j < getSitesToDigg(); j++) {
				String url = urlPrefix + j + urlSuffix;
				String name = htmlDir + "/" + url.replace("http://", "").replace("/", "_") + ".html";
				
				log.debug("Downloading url={}, filePath={}", url, name);
				
				if (!getFileDownloader().download(url, name)) {
					log.error("Error while downloading site url={}", url);
					throw new RuntimeException("Error while downloading site, see logs for more info");
				}
				try {
					Thread.sleep(rand.nextInt(1000));
				} catch (InterruptedException e) {
					log.error("Sleeping between downloading html sites interupted", e);
					throw new RuntimeException(e);
				}
			}
		}
	}
	

}
